from django.db import models
from django.db.models import permalink
from django.contrib.auth.models import User
from djangopolymorphicmodels.models import DowncastMetaclass

"""
Labyrinth data types and class definition
"""

LABYRINTH_TYPES = (
    ('game', 'Game'),
    ('key', 'Key Feature Problem'),
)

ACCESS_TYPES = (
    ('open', 'Open'),
    ('closed', 'Closed'),
    ('private', 'Private'),
    ('password', 'Password'),
)

SECTION_BROWSING_TYPES = (
    ('off', 'Off'),
    ('visible', 'Visible'),
    ('navigable', 'Navigable'),
)

BOOLEAN_TYPES = (
    ('and', 'and'),
    ('or', 'or'),
)

class Labyrinth(models.Model):
    name = models.CharField(max_length=64)
    keywords = models.CharField(max_length=64, null=True, blank=True)
    authors = models.ManyToManyField(User)
    credits = models.TextField(null=True, blank=True)
    time_limit = models.IntegerField(null=True, blank=True, help_text='Leave blank to forego time restriction.')
    type = models.CharField(max_length=9, choices=LABYRINTH_TYPES, default='maze')
    root_node = models.OneToOneField('Node', null=True, blank=True, related_name='root_nodes')
    skin = models.ForeignKey('Skin')
    access = models.CharField(max_length=7, choices=ACCESS_TYPES, default='open')
    password = models.CharField(max_length=64, null=True, blank=True)
    section_browsing = models.CharField(max_length=9, choices=SECTION_BROWSING_TYPES, default='off')
    
    def __unicode__(self):
        return "%d: %s" % (self.id, self.name)
    
    @permalink
    def get_absolute_url(self):
        return ('ol-readLabyrinth', [str(self.id)])

"""
Node data types and class definition
"""

LINK_STYLES = (
    ('text', 'Text'),
    ('select', 'Select List'),
    ('confidence', 'Select List & Confidence'),
    ('manual', 'Manual Entry'),
)

NODE_TYPES = (
    ('normal', 'Normal'),
    ('avoid', 'Must Avoid'),
    ('visit', 'Must Visit'),
)

class Node(models.Model):
    title = models.CharField(max_length=128)
    labyrinth = models.ForeignKey('Labyrinth')
    message = models.TextField()
    supporting_information = models.TextField(null=True, blank=True)
    random_outbound_link = models.BooleanField()
    undo = models.BooleanField()
    link_style = models.CharField(max_length=10, choices=LINK_STYLES, default='text')
    type = models.CharField(max_length=6, choices=NODE_TYPES, default='normal')
    avatar = models.ForeignKey('Avatar', null=True, blank=True)
    section = models.ForeignKey('Section', null=True, blank=True)
    section_index = models.PositiveIntegerField(null=True, blank=True)
    x_position = models.PositiveIntegerField(null=True, blank=True)
    y_position = models.PositiveIntegerField(null=True, blank=True)
    color = models.PositiveIntegerField(null=True, blank=True)
    
    def __unicode__(self):
        return "%d: %s" % (self.id, self.title)
    
    @permalink
    def get_absolute_url(self):
        return ('ol-updateNode', [str(self.labyrinth.id), str(self.id)])

class Link(models.Model):
    label = models.CharField(max_length=64, null=True, blank=True)
    labyrinth = models.ForeignKey('Labyrinth')
    icon = models.ImageField(upload_to='assets', null=True, blank=True)
    source = models.ForeignKey('Node', related_name='outgoing_links')
    destination = models.ForeignKey('Node', related_name='incoming_links')
    
    def __unicode__(self):
        return "%d: %s (%s to %s)" % (self.id, self.label, self.source, self.destination)
    
    @permalink
    def get_absolute_url(self):
        return ('ol-updateLink', [str(self.labyrinth.id), str(self.source.id), str(self.id)])

"""
Counter data types and class definition
"""

UNIT_TYPES = (
    ('percentage', 'Percentage'),
    ('kiloliters', 'Kiloliters'),
    ('liters', 'Liters'),
    ('centiliters', 'Centiliters'),
    ('milliliters', 'Milliliters'),
    ('pints', 'Pints'),
    ('quarts', 'Quarts'),
    ('fluid ounces', 'Fluid Ounces'),
    ('kilometers', 'Kilometers'),
    ('meters', 'Meters'),
    ('centimeters', 'Centimeters'),
    ('millimeters', 'Millimeters'),
    ('micrometers', 'Micrometers'),
    ('miles', 'Miles'),
    ('feet', 'Feet'),
    ('inches', 'Inches'),
    ('kilograms', 'Kilograms'),
    ('grams', 'Grams'),
    ('centigrams', 'Centigrams'),
    ('milligrams', 'Milligrams'),
    ('pounds', 'Pounds'),
    ('ounces', 'Ounces'),
    ('timestamp', 'Timestamp'),
    ('years', 'Years'),
    ('months', 'Months'),
    ('days', 'Days'),
    ('hours', 'Hours'),
    ('minutes', 'Minutes'),
    ('seconds', 'Seconds'),
    ('milliseconds', 'Milliseconds'),
    ('microseconds', 'Microseconds'),
    ('nanoseconds', 'Nanoseconds'),
    ('centigrades', 'Centigrades'),
    ('fahrenheit', 'Fahrenheit'),
)

class Counter(models.Model):
    name = models.CharField(max_length=64)
    labyrinth = models.ForeignKey('Labyrinth')
    description = models.TextField(null=True, blank=True)
    start_value = models.IntegerField()
    unit = models.CharField(null=True, blank=True, max_length=20, choices=UNIT_TYPES)
    visible = models.BooleanField()
    
    def __unicode__(self):
        return "%d: %s" % (self.id, self.name)
    
    @permalink
    def get_absolute_url(self):
        return ('ol-updateCounter', [str(self.labyrinth.id), str(self.id)])

class NodeCondition(models.Model):
    node = models.OneToOneField('Node', related_name='condition')
    nodes = models.ManyToManyField('Node', related_name='referencing_conditions')
    operation = models.CharField(max_length=3, choices=BOOLEAN_TYPES)
    message = models.TextField(null=True, blank=True)

VARIANCE_OPERATION_TYPES = (
    ('=', 'Equate'),
    ('+', 'Add'),
    ('-', 'Subtract'),
)
    
class NodeVariance(models.Model):
    node = models.ForeignKey('Node')
    counter = models.ForeignKey('Counter')
    operation = models.CharField(max_length=1, choices=VARIANCE_OPERATION_TYPES)
    operation_value = models.PositiveIntegerField()
    
class LinkVariance(models.Model):
    link = models.ForeignKey('Link')
    counter = models.ForeignKey('Counter')
    operation = models.CharField(max_length=1, choices=VARIANCE_OPERATION_TYPES)
    operation_value = models.PositiveIntegerField()
    

COMPARISON_TYPES = (
    ('<', 'less than'),
    ('<=', 'less than or equal to'),
    ('==', 'equal to'),
    ('!=', 'not equal to'),
    ('>=', 'greater than or equal to'),
    ('>', 'greater than'),
)

class Alert(models.Model):
    name = models.CharField(max_length=64)
    counter = models.ForeignKey('Counter')
    comparison = models.CharField(max_length=2, choices=COMPARISON_TYPES)
    comparison_value = models.PositiveIntegerField()
    message = models.TextField()
    end_labyrinth = models.BooleanField()
    
    def __unicode__(self):
        return "%d: %s" % (self.id, self.name)

"""
Feedback types and class definition
"""

FEEDBACK_TYPES = (
    ('general', 'General'),
    ('time', 'Time Based'),
    ('node', 'Node Based'),
    ('node_type', 'Node Type Based'),
    ('counter', 'Counter Based'),
)

class Feedback(models.Model):
    name = models.CharField(max_length=64)
    labyrinth = models.ForeignKey(Labyrinth)
    type = models.CharField(max_length=9, choices=FEEDBACK_TYPES, default='general')
    message = models.TextField()
    comparison = models.CharField(max_length=2, choices=COMPARISON_TYPES, default='<')
    comparison_value = models.PositiveIntegerField(null=True, blank=True)
    node = models.ForeignKey('Node', null=True, blank=True)
    counter = models.ForeignKey('Counter', null=True, blank=True)
    node_type = models.CharField(max_length=6, choices=NODE_TYPES[1:], default='avoid')
    
    def __unicode__(self):
        return "%d: %s" % (self.id, self.name)
    
    @permalink
    def get_absolute_url(self):
        return ('ol-updateFeedback', [str(self.labyrinth.id), str(self.id)])


QUESTION_TYPES = (
    ('single', 'Single-Line'),
    ('multi', 'Multi-Line'),
)

QUESTION_WIDTHS = (
    (10, '10'),
    (20, '20'),
    (40, '40'),
    (60, '60'),
)

QUESTION_HEIGHTS = (
    (2, '2'),
    (4, '4'),
    (6, '6'),
    (8, '8'),
)

class Question(models.Model):
    stem = models.TextField()
    labyrinth = models.ForeignKey(Labyrinth)
    type = models.CharField(max_length=6, choices=QUESTION_TYPES, default='single')
    width = models.PositiveSmallIntegerField(choices=QUESTION_WIDTHS, default=10)
    height = models.PositiveSmallIntegerField(choices=QUESTION_HEIGHTS, default=2)
    
    def __unicode__(self):
        return "%d: %s" % (self.id, self.stem)
    
    @permalink
    def get_absolute_url(self):
        return ('ol-updateQuestion', [str(self.labyrinth.id), str(self.id)])

"""
Asset data types and class definition
"""

ASSET_TYPES = (
    ('image', 'Image'),
    ('link', 'Acrobat PDF'), #.pdf
    ('shockwave_flash', 'Shockwave Flash'), #.swf
    ('link', 'Microsoft Word'), #.doc
    ('link', 'Microsoft Excel'), #.xls
    ('link', 'Microsoft PowerPoint'), #.ppt
    ('link', 'Rich Text Format'),
    ('quicktime_video', 'QuickTime Video'),
    ('mpeg4_video', 'MPEG-4 Video'),
    ('windows_media_video', 'Windows Media Video'),
    ('real_stream_ram_video', 'Real Stream (RAM) Video'), #.ram
    ('real_stream_rpm_video', 'Real Stream (RPM) Video'), #.rpm
    ('flash_video', 'Flash Video'), #.flv
    ('mp3_audio', 'MP3 Audio'), #.mp3
    ('wav_audio', 'WAV Audio'), #.wav
    ('aac_audio', 'AAC (m4a) Audio'),
)

class Asset(models.Model):
    name = models.CharField(max_length=64)
    labyrinth = models.ForeignKey('Labyrinth')
    file = models.FileField(upload_to='assets')
    type = models.CharField(max_length=27, choices=ASSET_TYPES)
    description = models.TextField(null=True, blank=True)
    
    def __unicode__(self):
        return "%d: %s" % (self.id, self.name)
    
    @permalink
    def get_absolute_url(self):
        return ('ol-updateAsset', [str(self.labyrinth.id), str(self.id)])

class Section(models.Model):
    name = models.CharField(max_length=64)
    labyrinth = models.ForeignKey('Labyrinth')
    
    def __unicode__(self):
        return "%d: %s" % (self.id, self.name)
    
    @permalink
    def get_absolute_url(self):
        return ('ol-updateSection', [str(self.labyrinth.id), str(self.id)])

OUTFIT_TYPES = (
    ('A', 'Naked'),
    ('B', 'Wooly Jumper'),
    ('C', 'Shirt and Tie'),
    ('D', 'Nurse Uniform'),
    ('E', 'Scrubs (Blue)'),
    ('F', 'Scrubs (Green)'),
    ('G', 'Vest'),
    ('H', 'Gown (White)'),
    ('I', 'Pyjamas (Female)'),
    ('J', 'Pyjamas (Male)'),
    ('K', 'Doctor (Male)'),
    ('L', 'Doctor (Female)'),
    ('M', 'Pattern Turtle Neck'),
    ('N', 'Black Striped Shirt'),
    ('O', 'Winter Jacket'),
    ('P', 'V-Neck'),
    ('Q', 'Fleece'),
    ('R', 'Sweater')
)

HAIR_TYPES = (
    ('A', 'Bald'),
    ('B', 'Shaved'),
    ('C', 'Long/Blonde'),
    ('D', 'Short'),
    ('E', 'Curly'),
    ('F', 'Bob'),
    ('G', 'Long/Red'),
    ('H', 'Grandpa'),
    ('I', 'Granny'),
    ('K', 'Young Man'),
    ('L', 'Long')
)

ENVIRONMENT_TYPES = (
    ('A', 'None'),
    ('B', 'Ambulance Bay'),
    ('C', 'Residential Street'),
    ('D', 'Living Room'),
    ('E', 'High Street'),
    ('F', 'Bed/Pillow'),
    ('G', 'Hospital Corridor'),
    ('H', 'Waiting Room'),
    ('I', 'City Skyline'),
    ('J', 'Inside Ambulance'),
    ('K', 'Basic Office'),
    ('L', 'Lakeside'),
    ('M', 'Suburbs'),
    ('N', 'Basic Room'),
    ('O', 'X-Ray'),
    ('P', 'Downtown'),
    ('Q', 'Winter'),
    ('R', 'CA Ambulance'),
    ('S', 'Medivac Helicopter'),
    ('T', 'Summer'),
    ('U', 'Long Road'),
    ('W', 'Outside Lake'),
    ('X', 'Field'),
    ('Y', 'Corridor'),
    ('Z', 'Roadside'),
    ('AA', 'Room'),
    ('BB', 'Sign'),
    ('CC', 'Bedside'),
    ('DD', 'Ambulance 2'),
    ('EE', 'Yield Sign'),
    ('FF', 'Machine'),
    ('GG', 'Pillow B'),
    ('HH', 'Forest River'),
    ('II', 'Parking Lot'),
    ('JJ', 'Concourse'),
    ('KK', 'Office Cubicle')
)

ACCESSORY_TYPES = (
    ('A', 'None'),
    ('B', 'Glasses'),
    ('C', 'Bindi'),
    ('D', 'Moustache'),
    ('E', 'Freckles'),
    ('F', 'Mask'),
    ('G', 'Blusher'),
    ('H', 'Earrings'),
    ('I', 'Beads'),
    ('J', 'Neckerchief'),
    ('K', 'Stethoscope'),
    ('L', 'Oxygen Mask'),
    ('M', 'Surgeon Cap'),
    ('N', 'Eye Patch'),
    ('O', 'Scratches'),
    ('P', 'Split Lip'),
    ('Q', 'Black Eye (Left)'),
    ('R', 'Black Eye (Right)'),
    ('S', 'Head Bandage'),
    ('T', 'Sunglasses'),
    ('U', 'Neck Brace'),
    ('W', 'Tears - Small'),
    ('X', 'Sweat'),
    ('Y', 'Beanie'),
    ('AA', 'Button Scarf'),
    ('BB', 'Tears - Large'),
    ('CC', 'Baseball Cap'),
    ('DD', 'Winter Hat')
)

class Avatar(models.Model):
    title = models.CharField(max_length=64)
    labyrinth = models.ForeignKey('Labyrinth')
    description = models.TextField(null=True, blank=True)
    sex = models.CharField(max_length=1, choices=(('A', 'Male'),('B', 'Female')), default='A')
    mouth_shape = models.CharField(max_length=1, choices=(('A', 'Smile'),('B', 'Indifferent'),('C', 'Frown')), default='A')
    age = models.CharField(max_length=1, choices=(('A', '20+'),('B', '40+'),('C', '60+')), default='A')
    eyes = models.CharField(max_length=1, choices=(('A', 'Open'),('B', 'Closed')), default='A')
    outfit = models.CharField(max_length=1, choices=OUTFIT_TYPES, default='P')
    outfit_color = models.CharField(max_length=6, default='993300')
    nose_type = models.CharField(max_length=1, choices=(('A', 'Nostrils Only'),('B', 'Petite'),('C', 'Wide')), default='B')
    hair_type = models.CharField(max_length=1, choices=HAIR_TYPES, default='K')
    hair_color = models.CharField(max_length=6, default='6F4900')
    accessory_1 = models.CharField(max_length=2, choices=ACCESSORY_TYPES, default='A')
    accessory_2 = models.CharField(max_length=2, choices=ACCESSORY_TYPES, default='A')
    accessory_3 = models.CharField(max_length=2, choices=ACCESSORY_TYPES, default='A')
    skin_tone_fill = models.CharField(max_length=6, default='DEBB78')
    skin_tone_outline = models.CharField(max_length=6, default='D09A32')
    background_color = models.CharField(max_length=6, default='99CCFF')
    environment = models.CharField(max_length=2, choices=ENVIRONMENT_TYPES, default='A')
    weather = models.CharField(max_length=1, choices=(('A', 'None'),('B', 'Rainy Day'),('C', 'Windy Day'),('D', 'Snowy Day')), default='A')
    speech_bubble = models.CharField(max_length=1, choices=(('A', 'None'),('B', 'Normal'),('C', 'Think'),('D', 'Shout')), default='A')
    speech_bubble_text = models.CharField(max_length=64, null=True, blank=True)
    
    def __unicode__(self):
        return "%d: %s" % (self.id, self.title)
    
    @permalink
    def get_absolute_url(self):
        return ('ol-updateAvatar', [str(self.labyrinth.id), str(self.id)])
    
    def get_parameters(self):
        return {
            'fSex': self.sex,
            'fMouth': self.mouth_shape,
            'fAge': self.age,
            'fEyes': self.eyes,
            'fOutfit': self.outfit,
            'fCloth': self.outfit_color,
            'fNose': self.nose_type,
            'fHair': self.hair_type,
            'fHairColor': self.hair_color,
            'fAccessory1': self.accessory_1,
            'fAccessory2': self.accessory_2,
            'fAccessory3': self.accessory_3,
            'fSkin': self.skin_tone_fill,
            'fSkinOut': self.skin_tone_outline,
            'fBkd': self.background_color,
            'fEnvironment': self.environment,
            'fWeather': self.weather,
            'fBubble': self.speech_bubble,
            'fBubbleText': self.speech_bubble_text
        }

class RemoteStateObserver(models.Model):
    enabled = models.BooleanField()
    labyrinth = models.ForeignKey(Labyrinth)
    name = models.CharField(max_length=64)
    hostname = models.CharField(max_length=64)
    port = models.IntegerField()
    
    def __unicode__(self):
        return "%d: %s" % (self.id, self.name)
    
    @permalink
    def get_absolute_url(self):
        return ('ol-updateRemoteStateObserver', [str(self.labyrinth.id), str(self.id)])

class Skin(models.Model):
    name = models.CharField(max_length=64)
    description = models.TextField(null=True, blank=True)
    
    def __unicode__(self):
        return "%d: %s" % (self.id, self.name)
    
    @permalink
    def get_absolute_url(self):
        return ('ol-updateSkin', [str(self.id)])

'''
Reporting classes

These classes provide logging functionality for labyrinths, and are used
to generate reports for any labyrinths completed with more than 3 links.
'''

class Report(models.Model):
    session_id = models.CharField(max_length=32)
    start_time = models.DateTimeField(auto_now_add=True)
    user = models.ForeignKey(User, null=True)
    labyrinth = models.ForeignKey(Labyrinth)
    
    def __unicode__(self):
        return "%d: %s (%s)" % (self.id, str(self.user), str(self.start_time))
    
    @permalink
    def get_absolute_url(self):
        return ('ol-readReport', [str(self.labyrinth.id), str(self.id)])
    
    class Meta:
        ordering = ['-start_time']

class NodeRecord(models.Model):
    report = models.ForeignKey(Report)
    node = models.ForeignKey(Node)
    timestamp = models.DateTimeField(auto_now_add=True)

class CounterRecord(models.Model):
    node_record = models.ForeignKey(NodeRecord)
    counter = models.ForeignKey(Counter)
    counter_value = models.IntegerField()

#############################
# MVP Classes
#############################

VPD_TEXT_TYPES = (
    ('narrative', 'Narrative'),
    ('chief complaint', 'Chief Complaint'),
    ('history', 'History'),
    ('problem', 'Problem'),
    ('allergy', 'Allergy'),
)

VPD_STRUCTURED_PATIENT_DEMOGRAPHIC_TYPES = (
    ('PatientID', 'Patient ID'),
    ('Name', 'Name'),
    ('Age', 'Age'),
    ('Sex', 'Sex'),
    ('Race', 'Race'),
    ('Species', 'Species'),
    ('Breed', 'Breed')
)

VPD_DIFFERENTIAL_DIAGNOSIS_LIKELIHOOD = (
    ('high', 'High'),
    ('medium', 'Medium'),
    ('low', 'Low'),
    ('none', 'None')
)

VPD_INTERVENTION_APPROPRIATENESS = (
    ('always', 'Always'),
    ('ok', 'Ok'),
    ('never', 'Never'),
    ('none', 'None')
)

VPD_ORIENTATION_TYPES_0 = (
    ('proximal', 'Proximal'),
    ('distal', 'Distal')
)

VPD_ORIENTATION_TYPES_1 = (
    ('right', 'Right'),
    ('left', 'Left')
)

VPD_ORIENTATION_TYPES_2 = (
    ('front', 'Front'),
    ('back', 'Back')
)

VPD_ORIENTATION_TYPES_3 = (
    ('inferior', 'Inferior'),
    ('superior', 'Superior')
)

class Element(models.Model):
    labyrinth = models.ForeignKey('Labyrinth')
    
    def __unicode__(self):
        return "%s (%d)" % (self.__class__.__name__, self.id)
    
    @permalink
    def get_absolute_url(self):
        return ('ol-updateElement', [str(self.labyrinth.id), str(self.id), str(self.__class__.__name__)])
    
    @permalink
    def get_delete_url(self):
        return ('ol-deleteElement', [str(self.labyrinth.id), str(self.id), str(self.__class__.__name__)])
    
    class Meta:
        abstract = True

class VPDText(Element):
    type = models.CharField(max_length=15, choices=VPD_TEXT_TYPES)
    text = models.TextField()

class StructuredPatientDemographics(Element):
    type = models.CharField(max_length=9, choices=VPD_STRUCTURED_PATIENT_DEMOGRAPHIC_TYPES)
    text = models.CharField(max_length=64)

class UnstructuredPatientDemographics(Element):
    title = models.CharField(max_length=64)
    description = models.CharField(max_length=255)

class AuthorDiagnoses(Element):
    title = models.CharField(max_length=64)
    description = models.CharField(max_length=255)

class Medication(Element):
    title = models.CharField(max_length=64)
    dose = models.CharField(max_length=64)
    route = models.CharField(max_length=64)
    frequency = models.CharField(max_length=64)
    item_source = models.CharField(max_length=64)
    item_source_id = models.CharField(max_length=64)

class InterviewItem(Element):
    question = models.CharField(max_length=64)
    answer = models.CharField(max_length=64)
    media = models.ForeignKey('Asset')
    trigger = models.BooleanField()

class PhysicalExam(Element):
    name = models.CharField(max_length=64)
    description = models.CharField(max_length=255)
    location = models.CharField(max_length=64)
    action = models.CharField(max_length=64)
    orientation_0 = models.CharField(max_length=8, choices=VPD_ORIENTATION_TYPES_0)
    orientation_1 = models.CharField(max_length=5, choices=VPD_ORIENTATION_TYPES_1)
    orientation_2 = models.CharField(max_length=5, choices=VPD_ORIENTATION_TYPES_2)
    orientation_3 = models.CharField(max_length=8, choices=VPD_ORIENTATION_TYPES_3)
    finding_name = models.CharField(max_length=64)
    finding_description = models.CharField(max_length=64)
    media = models.ForeignKey('Asset')

class DiagnosticTest(Element):
    name = models.CharField(max_length=64)
    description = models.CharField(max_length=255)
    units = models.CharField(max_length=64)
    result = models.CharField(max_length=64)
    normal_value = models.CharField(max_length=64)
    media = models.ForeignKey('Asset')

class DifferentialDiagnosis(Element):
    title = models.CharField(max_length=64)
    description = models.TextField()
    likelihood = models.CharField(max_length=6, choices=VPD_DIFFERENTIAL_DIAGNOSIS_LIKELIHOOD)

class Intervention(Element):
    title = models.CharField(max_length=64)
    description = models.CharField(max_length=255)
    medication_title = models.CharField(max_length=64)
    dose = models.CharField(max_length=64)
    route = models.CharField(max_length=64)
    frequency = models.CharField(max_length=64)
    item_source = models.CharField(max_length=64)
    item_source_id = models.CharField(max_length=64)
    appropriateness = models.CharField(max_length=64, choices=VPD_INTERVENTION_APPROPRIATENESS)
    results_title = models.CharField(max_length=64)
    results_description = models.TextField()
    media = models.ForeignKey('Asset')

class Cluster(models.Model):
    name = models.CharField(max_length=64)
    labyrinth = models.ForeignKey('Labyrinth')
    
    def __unicode__(self):
        return "%d: %s" % (self.id, self.name)
    
    @permalink
    def get_absolute_url(self):
        return ('ol-updateCluster', [str(self.labyrinth.id), str(self.id)])

CLUSTER_ITEM_TRIGGER_TYPES = (
    ('immediately', 'Immediately'),
    ('ontrigger', 'On Trigger'),
    ('delayed', 'Delayed'),
    ('ifrequested', 'If Requested')
)

class ClusterItem(models.Model):
    cluster = models.ForeignKey('Cluster')
    index = models.PositiveIntegerField()
    trigger = models.CharField(max_length=11, choices=CLUSTER_ITEM_TRIGGER_TYPES, null=True, blank=True)
    class_name = models.CharField(max_length=128)
    object_id = models.PositiveIntegerField()
    
    def __unicode__(self):
        if self.trigger:
            return "%s (%d) [%s] - %d" % (self.class_name, self.object_id, self.trigger, self.id)
        else:
            return "%s (%d) - %d" % (self.class_name, self.object_id, self.id)
    
    @permalink
    def get_absolute_url(self):
        return ('ol-deleteClusterItem', [str(self.cluster.labyrinth.id), str(self.cluster.id), str(self.id)])